#ifndef SM3_H
#define SM3_H

#include <stdint.h>
#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

#define SM3_DIGEST_LENGTH	32
#define SM3_BLOCK_SIZE		64
#define SM3_CBLOCK          (SM3_BLOCK_SIZE)
#define SM3_HMAC_SIZE		(SM3_DIGEST_LENGTH)

/**
 * sm3 example:
 *   sm3_ctx_t ctx;
 *   sm3_init(&ctx);
 *   sm3_update(&ctx, (const unsigned char*)"data", 4);
 *   unsigned char digest[SM3_DIGEST_LENGTH] output;
 *   sm3_final(&ctx, output);
 */
typedef struct
{
    uint32_t digest[8];
    int nblocks;
    unsigned char block[64];
    int num;
} sm3_ctx_t;

void sm3_init(sm3_ctx_t* ctx);
void sm3_update(sm3_ctx_t* ctx, const unsigned char* data, size_t data_len);
void sm3_final(sm3_ctx_t* ctx, unsigned char digest[SM3_DIGEST_LENGTH]);
void sm3_compress(uint32_t digest[8], const unsigned char block[SM3_BLOCK_SIZE]);
void sm3(const unsigned char *data, size_t datalen,
         unsigned char digest[SM3_DIGEST_LENGTH]);


/**
 * sm3_hmac example:
 *   sm3_ctx_t ctx;
 *   sm3_hmac_init(&ctx, (const unsigned char*)"key", 3);
 *   sm3_hmac_update(&ctx, (const unsigned char*)"data", 4);
 *   unsigned char digest[SM3_DIGEST_LENGTH] output;
 *   sm3_hmac_final(&ctx, output);
 */
typedef struct
{
    sm3_ctx_t sm3_ctx;
    unsigned char key[SM3_BLOCK_SIZE];
} sm3_hmac_ctx_t;

void sm3_hmac_init(sm3_hmac_ctx_t* ctx, const unsigned char* key, size_t key_len);
void sm3_hmac_update(sm3_hmac_ctx_t* ctx, const unsigned char* data, size_t data_len);
void sm3_hmac_final(sm3_hmac_ctx_t* ctx, unsigned char mac[SM3_HMAC_SIZE]);
void sm3_hmac(const unsigned char* data, size_t data_len,
              const unsigned char* key, size_t key_len,
              unsigned char mac[SM3_HMAC_SIZE]);

#ifdef __cplusplus
}
#endif

#endif // SM3_H
